package bp.difference.redis;

import bp.da.Log;
import bp.tools.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.ReadMode;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.redisson.config.Config;
import org.springframework.core.env.Environment;

@Configuration
@ConditionalOnProperty(name="spring.data.redis.repositories.enabled", havingValue="true", matchIfMissing=true)
public class RedisConfig
{
    // logger
    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);

    @Autowired
    Environment env;
    private int timeout = 2000;
    private int scanInterval = 60000;
    private static final String ADDRESS_PREFIX = "redis://";

    @Bean(destroyMethod = "shutdown")
    public RedissonClient initBean() {
        String host =  env.getProperty("spring.redis.host");
        String port =  env.getProperty("spring.redis.port");
        String password =  env.getProperty("spring.redis.password");
        String databaseStr = env.getProperty("spring.redis.database", "0");
        int database = Integer.parseInt(databaseStr);

        String sentinelNodes = env.getProperty("spring.redis.sentinel.nodes");
        String masterName = env.getProperty("spring.redis.sentinel.master");

        String clusterNodes = env.getProperty("spring.redis.cluster.nodes");

        if (StringUtils.isNotBlank(sentinelNodes)) {
            logger.info("Redis is sentinel mode");
            return redissonSentinel(sentinelNodes, masterName, password, database);
        }
        if (StringUtils.isNotBlank(clusterNodes)) {
            logger.info("Redis is cluster mode");
            return redissonCluster(clusterNodes, password);
        }
        if (StringUtils.isNotBlank(host)) {
            logger.info("Redis is single mode");
            return redissonSingle(host, port, password, database);
        }

        logger.info("Redisson config can not find any valid redis mode");
        return null;
    }

    private RedissonClient redissonSingle(String host, String port, String password, int database) {
        Config config = new Config();
        String address = ADDRESS_PREFIX + host + ":" + port;
        SingleServerConfig singleServerConfig = config.useSingleServer()
                .setAddress(address)
                .setTimeout(timeout)
                .setDatabase(database);

        if (StringUtils.isNotBlank(password)) {
            singleServerConfig.setPassword(password);
        }
        return Redisson.create(config);
    }

    private RedissonClient redissonSentinel(String sentinelNodes, String masterName, String password, int database) {
        Config config = new Config();
        String[] nodes = sentinelNodes.split(",");
        for (int i = 0; i < nodes.length; i++) {
            nodes[i] = ADDRESS_PREFIX + nodes[i].trim();
        }

        // 使用具体的类型 SentinelServersConfig 替换 var
        SentinelServersConfig sentinelServersConfig = config.useSentinelServers()
                .setMasterName(masterName)
                .addSentinelAddress(nodes)
                .setTimeout(timeout)
                .setDatabase(database)
                .setCheckSentinelsList(false);

        if (StringUtils.isNotBlank(password)) {
            sentinelServersConfig.setPassword(password);
        }
        return Redisson.create(config);
    }

    private RedissonClient redissonCluster(String clusterNodes, String password) {
        Config config = new Config();
        String[] nodes = clusterNodes.split(",");
        for (int i = 0; i < nodes.length; i++) {
            nodes[i] = ADDRESS_PREFIX + nodes[i].trim();
        }

        // 使用具体的类型 ClusterServersConfig 替换 var
        ClusterServersConfig clusterServersConfig = config.useClusterServers()
                .setScanInterval(scanInterval)
                .addNodeAddress(nodes)
                .setReadMode(ReadMode.MASTER);

        if (StringUtils.isNotBlank(password)) {
            clusterServersConfig.setPassword(password);
        }
        return Redisson.create(config);
    }
}